package com.zebra.gateway.processor;

import com.zebra.gateway.GwConfigInfoManager;
import com.zebra.gateway.protocol.GatewayCommand;
import com.zebra.gateway.protocol.GatewaySendMessageUtil;
import com.zebra.gateway.session.LoginSessionManager;
import com.zebra.gateway.session.Session;
import com.zebra.gateway.session.SessionManager;
import com.zebra.remoting.config.StateCode;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.ProcessorType;
import com.zebra.remoting.util.RemotingUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 *  网关 不知道进入游戏规则; 所以, 不做切换服务器, 还是由前端自己做操作
 */
public class ServerLobbyHandlerProcessor extends AbstractGatewayProcessor {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerLobbyHandlerProcessor.class);

    @Override
    public void doProcess(ChannelHandlerContext ctx, GatewayCommand msg) throws  Exception {
        ProcessorType processorType = msg.getProcessorType();
        switch (processorType){
            case GM:      { doGM(ctx, msg);      break; }
            case L_LOGIN: { doL_LOGIN(ctx, msg); break; }
            case L_RECON: { doL_RECON(ctx, msg); break; } // 重连是断开了GW channel 重连链接
            case L_EXIT:  { doL_EXIT(ctx, msg);  break; }
            default:      {  doGM(ctx, msg); }
        }
    }

    //大厅 登录----第一次进入TMS 服务器
    private void doL_LOGIN(ChannelHandlerContext ctx, GatewayCommand msg)throws  Exception{
        logger.warn("LOBBY L_LOGIN {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getUserId() <1 || msg.getToken() < 1){
            logger.error("LOBBY L_LOGIN ParamInvalid {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }

        //---向注册中心-发同步消息-获取地址-------
        Connection tmsConnection =  getTmsConnection(msg.getUserId(), msg.getToken(), msg.getCmd(), (short) 0, ProcessorType.L_LOGIN);
        tmsConnection.writeAndFlush(msg);

        //放登录消息到Temp Session
        Session session = new Session(ctx.channel());
        session.setUserId(msg.getUserId());
        LoginSessionManager.LOGINSESSION.putSession(session);

    }

    //  重连如果已经有用户在线则需要提示该用户在线; 不能重连
    private void doL_RECON(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("LOBBY L_RECON {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getUserId() <1 || msg.getToken() < 1){
            logger.error("LOBBY L_RECON TOKEN OR UID is null {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }

        Session session = SessionManager.getInstance().getSession(msg.getUserId());
        if (null == session){
            Connection tmsConnection = getTmsConnection(msg.getUserId(), msg.getToken(), msg.getCmd(), (short) 0, ProcessorType.L_RECON);   // 如果重连异常 不能 发消息到 TMS 让其下线;  因为可能又正常玩家，顶掉了;
            tmsConnection.writeAndFlush(msg);

            session = new Session(ctx.channel());
            session.setUserId(msg.getUserId());
            LoginSessionManager.LOGINSESSION.putSession(session);
            return;
        }

        if (msg.getToken() != session.getToken()){
            logger.error("LOBBY L_RECON SESSION not disagree 2;  {} {}; token:{} isClose:{}",  RemotingUtil.channelToString(ctx.channel()), msg.toString(), session.getToken(), session.isWeakClose());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.LoginUn.code()); //---不需要处理---
            return;
        }

        Connection connection = getConnection(session, msg.getCmd(), ProcessorType.L_RECON); //  如果重连异常 不能 发消息到 TMS 让其下线;  因为可能又正常玩家，顶掉了;
        connection.writeAndFlush(msg);

        session.setChannel(ctx.channel());
        LoginSessionManager.LOGINSESSION.putSession(session);
    }

    private void doL_EXIT(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("LOBBY L_EXIT {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getToken() < 1){
            logger.error("LOBBY L_EXIT TOKEN is null {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }
        forwardMessage(ctx, msg);
    }


    private void doGM(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("LOBBY GM {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
        if (msg.getToken() < 1){
            logger.error("LOBBY GM TOKEN is null {} {}", RemotingUtil.channelToString(ctx.channel()), msg.toString());
            GatewaySendMessageUtil.sendStateMessage(ctx, msg, StateCode.ParamInvalid.code());
            return;
        }
        forwardMessage(ctx, msg);
    }

    private void forwardMessage(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        Session session = getSessionByServer(ctx, msg);
        if (null == session){
            return;
        }
        //TODO 此处 如果大厅请求 子游戏命令 则会报 null 异常
        Connection connection = getConnection(session, msg.getCmd(), ProcessorType.GM);
        connection.writeAndFlush(msg);
    }


    private Connection getConnection(Session session, int cmd, ProcessorType processorType) throws Exception {
        Connection connection = session.getLobbyConn();
        if (connection.isFine()){
            return connection;
        }

        Connection tmsConnection = getTmsConnection(session.getUserId(), session.getToken(), cmd, (short) 0, processorType);
        logger.warn("LOBBY get TMS connection to RA; processorType: {}  u: {} cmd: {} sid: {} tmsConn: {} ", processorType, session.getUserId(), cmd, connection.getServerId(), tmsConnection == null ? "tmsConnection is null" : tmsConnection.toString());
        sendSWITCHTMS(tmsConnection, session, processorType);
        session.setLobbyConn(tmsConnection);
        return tmsConnection;
    }



}
